package com.project.service.imp;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//代理工厂  执行（代理对象）的逻辑
public class ServiceProxyFactory implements InvocationHandler {
    private Object targetObj;
    private static SqlSessionFactory factory;
    static {
        try {
            Reader reader = Resources.getResourceAsReader("mybatis.cfg.xml");
            factory = new SqlSessionFactoryBuilder().build(reader);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public ServiceProxyFactory(Object targetObj) {
        this.targetObj = targetObj;
    }

    /**
     * 得到代理对象
     * @return  代理对象
     */
    public Object getProxy(){
        //3、使用 Proxy.newProxyInstance() 方法创建代理对象。这个方法需要三个参数
        return Proxy.newProxyInstance(
                targetObj.getClass().getClassLoader(), //目标对象 类加载器
                targetObj.getClass().getInterfaces(),//目标对象 实现的接口列表
                this//InvocationHandler 接口实现类对象，产生的目标对象在执行方法时，会执行InvocationHandler对象的invoke方法
        );
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //得到会话
        SqlSession session = factory.openSession();
        //得到目标对象属性列表
        Field[] fields = targetObj.getClass().getDeclaredFields();
        //遍历属性列表的方式获取每个属性的类型
        for (Field f: fields) {
            //判断这个属性是否为接口  getType方法返回：该属性的类型的 Class 对象
            if(f.getType().isInterface()){
                //产生接口实现类对象mapper
                Object mapper =session.getMapper(f.getType());
                System.out.println("--------------------------------------------------------"+f.getType());
                //去掉修饰符 检查
                f.setAccessible(true);
                //给目标对象的mapper属性 赋值
                f.set(targetObj,mapper);
            }
        }
        //执行目标对象的目标方法，传递实参，得到方法执行后的返回值
        Object returnObj = null;
        try{
            //调用目标对象的方法
            returnObj = method.invoke(targetObj,args);
            session.commit();
        }catch (Exception e){
            e.printStackTrace();
            session.rollback();
        }finally {
            session.close();
        }
        return returnObj;
    }
}
